﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;

/*
* 源码已托管：https://gitee.com/dlgcy/WPFTemplateLib
*/
namespace WPFTemplateLib.Enhance
{
	/// <summary>
	/// 支持批量修改（AddRange、RemoveRange）的 <see cref="ObservableCollection&lt;T>"/> <para/>
	/// 修改自：https://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/ 评论区 jody
	/// </summary>
	public class RangeObservableCollection<T> : ObservableCollection<T>
	{
		private bool _suppressNotification = false;

		/// <inheritdoc />
		protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
		{
			if (!_suppressNotification)
				base.OnCollectionChanged(e);
		}

		/// <summary>
		/// 批量更新开始（暂停事件通知；用于调用原生方法时；与 EndBatchUpdate 配套使用）
		/// </summary>
		public void BatchUpdate()
		{
			_suppressNotification = true;
		}

		/// <summary>
		/// 批量更新结束（恢复事件通知）
		/// </summary>
		public void EndBatchUpdate()
		{
			_suppressNotification = false;
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
		}

		/// <summary>
		/// 批量添加
		/// </summary>
		/// <param name="list">列表</param>
		/// <exception cref="ArgumentNullException">列表为 null 时引发</exception>
		public void AddRange(IEnumerable list)
		{
			if (list == null)
				throw new ArgumentNullException(nameof(list));

			var prevState = _suppressNotification;
			_suppressNotification = true;
			foreach (T item in list)
			{
				Add(item);
				//Items.Add(item); //Klus：它不会触发任何通知，并且不再需要 _suppressNotification【待验证】
			}

			_suppressNotification = prevState;
			//OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, list, null)); //会报错：只支持 Replace 操作;
			//OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, list)); //会报错：集合 Add 事件引用的项目不属于集合。
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
		}

		/// <summary>
		/// 批量移除
		/// </summary>
		/// <param name="list">列表</param>
		/// <exception cref="ArgumentNullException">列表为 null 时引发</exception>
		/// <example>
		///	<code>
		///	Rows.RemoveRange(Rows.ToList());
		/// </code>
		/// </example>
		public void RemoveRange(IEnumerable list)
		{
			if (list == null)
				throw new ArgumentNullException(nameof(list));

			var prevState = _suppressNotification;
			_suppressNotification = true;
			foreach (T item in list)
			{
				Remove(item);
			}

			_suppressNotification = prevState;
			//OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, list)); //会报错：无法找到已移除的项;
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
		}

		/// <summary>
		/// 批量清空
		/// </summary>
		public void ClearBatch()
		{
			//CheckReentrancy();
			var prevState = _suppressNotification;
			_suppressNotification = true;

			List<T> temp = new List<T>();
			temp.AddRange(Items);
			Items.Clear();
			_suppressNotification = prevState;
			//OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, temp)); //会报错：不支持范围操作;
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
		}
	}
}
